/**
 * \file deserializer.h
 * \brief Deserializer class implementation
 * \author Marc Laval
 * \version 0.1
 * \date 10/2011
 *
 */

#include "deserializer.h"

//----------------------------------------------------------------------
/*! \brief Standard constructor
 *  \param buf ByteBuffer containing command raw data
 */
Deserializer::Deserializer(ByteBuffer * buf)
{
	m_buf = buf;
	m_index = 0;
}

//----------------------------------------------------------------------
/*! \brief Resets current read index */
void Deserializer::reset()
{
	m_index = 0;
}

//----------------------------------------------------------------------
/*! \brief Deserializes an unsigned 8bit int from buffer
 *  \return data as an unsigned 8bit int
 */
uint8 Deserializer::readUInt8()
{
	if(m_buf == NULL)
		throw runtime_error("Byte buffer is NULL");

	if(m_index+sizeof(uint8) > m_buf->size())
		throw runtime_error("Not enough data remaining to read unsigned 8bits integer.");

	uint8 tmp = (*m_buf)[m_index];
	m_index++;

	return tmp;
}

//----------------------------------------------------------------------
/*! \brief Deserializes an unsigned 16bit int from buffer
 *  \return data as an unsigned 16bit int
 */
uint16 Deserializer::readUInt16()
{
	if(m_buf == NULL)
		throw runtime_error("Byte buffer is NULL");

	if(m_index+sizeof(uint16) > m_buf->size())
		throw runtime_error("Not enough data remaining to read unsigned 16bits integer.");

	uint16 tmp = (*m_buf)[m_index];
	m_index++;
	tmp |= ((*m_buf)[m_index] << 8);
	m_index++;

	return tmp;
}

//----------------------------------------------------------------------
/*! \brief Deserializes an unsigned 32bit int from buffer
 *  \return data as an unsigned 32bit int
 */
uint32 Deserializer::readUInt32()
{
	if(m_buf == NULL)
		throw runtime_error("Byte buffer is NULL");

	if(m_index+sizeof(uint32) > m_buf->size())
		throw runtime_error("Not enough data remaining to read unsigned 32bits integer.");

	uint32 tmp = (*m_buf)[m_index];
	m_index++;
	tmp |= ((*m_buf)[m_index] << 8);
	m_index++;
	tmp |= ((*m_buf)[m_index] << 16);
	m_index++;
	tmp |= ((*m_buf)[m_index] << 24);
	m_index++;

	return tmp;
}

//----------------------------------------------------------------------
/*! \brief Deserializes an unsigned 64bit int from buffer
 *  \return data as an unsigned 64bit int
 */
uint64 Deserializer::readUInt64()
{
	if(m_buf == NULL)
		throw runtime_error("Byte buffer is NULL");

	if(m_index+sizeof(uint64) > m_buf->size())
		throw runtime_error("Not enough data remaining to read unsigned 64bits integer.");

	uint64 tmp = (*m_buf)[m_index];
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 8);
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 16);
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 24);
	m_index++;

	tmp |= (((uint64)(*m_buf)[m_index]) << 32);
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 40);
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 48);
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 56);
	m_index++;

	return tmp;
}

//----------------------------------------------------------------------
/*! \brief Deserializes a boolean from buffer
 *  \return data as a boolean
 */
bool Deserializer::readBool()
{
	if(m_buf == NULL)
		throw runtime_error("Byte buffer is NULL");

	if(m_index+sizeof(uint8) > m_buf->size())
		throw runtime_error("Not enough data remaining to read boolean.");

	uint8 tmp = (*m_buf)[m_index];
	m_index++;

	return (tmp == 1);
}

//----------------------------------------------------------------------
/*! \brief Deserializes a float from buffer
 *  \return data as a float
 */
float Deserializer::readFloat()
{
	if(m_buf == NULL)
		throw runtime_error("Byte buffer is NULL");

	if(m_index+sizeof(uint32) > m_buf->size())
		throw runtime_error("Not enough data remaining to read float.");

	uint32 tmp = (*m_buf)[m_index];
	m_index++;
	tmp |= ((*m_buf)[m_index] << 8);
	m_index++;
	tmp |= ((*m_buf)[m_index] << 16);
	m_index++;
	tmp |= ((*m_buf)[m_index] << 24);
	m_index++;
	float val;
	val = *(float*) &tmp;

	return val;
}

//----------------------------------------------------------------------
/*! \brief Deserializes a double from buffer
 *  \return data as a double
 */
double Deserializer::readDouble()
{
	if(m_buf == NULL)
		throw runtime_error("Byte buffer is NULL");

	if(m_index+sizeof(uint64) > m_buf->size())
		throw runtime_error("Not enough data remaining to read double.");

	uint64 tmp = (*m_buf)[m_index];
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 8);
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 16);
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 24);
	m_index++;

	tmp |= (((uint64)(*m_buf)[m_index]) << 32);
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 40);
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 48);
	m_index++;
	tmp |= (((uint64)(*m_buf)[m_index]) << 56);
	m_index++;

	double val;
	val = *(double*) &tmp;

	return val;
}

//----------------------------------------------------------------------
/*! \brief Deserializes a string from buffer
 *  \return data as a string
 */
string Deserializer::readString()
{
	if(m_buf == NULL)
		throw runtime_error("Byte buffer is NULL");

	uint32 save_index = m_index;
	string str = "";
	char c = '0';

	while(c != NULL_CHAR && m_index < m_buf->size())
	{
		c = (char) (*m_buf)[m_index];
		m_index++;
		if(c != NULL_CHAR)
			str += c;
	}

	if(c != NULL_CHAR)
	{
		m_index = save_index;
		throw runtime_error("Error while deserializing string : Wrong string format");
	}

	return str;
}
